﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Media;

namespace HexTile
{
    public class HexTable
    {
        public class Tile
        {
            // All units on this tile
        }

        // All tiles
        private Tile[][] m_tiles;
        private Polyline[][] m_hexagons;

        ////////////////////////////////////////////
        // The members which will go in a derived class
        ////////////////////////////////////////////

        private int m_hCount;
        private int m_vCount;

        private static PointCollection Hexagon = null;

        private const double Sqrt2 = 1.41421356;
        private const double InvSqrt2 = 1 / Sqrt2;

        public HexTable(int hCount, int vCount)
        {
            m_hCount = hCount; m_vCount = vCount;

            m_tiles = new Tile[m_hCount][];
            m_hexagons = new Polyline[m_hCount][];
            for (int i = 0; i < m_hCount; ++i)
            {
                m_tiles[i] = new Tile[m_vCount];
                m_hexagons[i] = new Polyline[m_vCount];
                for (int j = 0; j < m_vCount; ++j)
                    m_tiles[i][j] = new Tile();
            }

            if (Hexagon == null)
                InitHexagon();

            Point pt = new Point() { X = 0, Y = 0 };
            for (int row = 0; row < m_vCount; ++row)
            {
                pt.X = 0;

                int colCount = m_hCount;
                // If this row is odd then it doesn't have the first half
                if (row % 2 == 1)
                {
                    pt.X -= InvSqrt2;
                    --colCount;
                }

                for (int col = 0; col < colCount; ++col)
                {
                    Polyline line = new Polyline();
                    line.Points = Hexagon;
                    m_hexagons[col][row] = line;

                    pt.X -= Sqrt2;
                }

                pt.Y -= (1 + InvSqrt2);
            }
        }

        public void SetRectangle(double width, double height)
        {
            double fx = width / (m_hCount * Sqrt2);
            double fy = height / (m_vCount * (1 + InvSqrt2));

            Point pt = new Point() { X = 0, Y = 0 };
            for (int row = 0; row < m_vCount; ++row)
            {
                pt.X = 0;

                int colCount = m_hCount;
                // If this row is odd then it doesn't have the first half
                if (row % 2 == 1)
                {
                    pt.X = InvSqrt2;
                    --colCount;
                }

                for (int col = 0; col < colCount; ++col)
                {
                    Polyline line = m_hexagons[col][row];
                    Matrix m = new Matrix();
                    m.Translate(pt.X, pt.Y);
                    m.Scale(fx, fy);
                    MatrixTransform mt = new MatrixTransform(m);
                    mt.Freeze();
                    line.RenderTransform = mt;

                    pt.X += Sqrt2;
                }

                pt.Y += (1 + InvSqrt2);
            }

        }

        private static void InitHexagon()
        {
            // assume that the vertice is of size 1
            Hexagon = new PointCollection(7);
            
            Hexagon.Add(new Point(InvSqrt2, 0));
            Hexagon.Add(new Point(0, InvSqrt2));
            Hexagon.Add(new Point(0, 1 + InvSqrt2));
            Hexagon.Add(new Point(InvSqrt2, 1 + Sqrt2));
            Hexagon.Add(new Point(Sqrt2, 1 + InvSqrt2));
            Hexagon.Add(new Point(Sqrt2, InvSqrt2));
            Hexagon.Add(new Point(InvSqrt2, 0));
            Hexagon.Freeze();
        }

        public List<Polyline> CreateLines()
        {
            List<Polyline> lst = new List<Polyline>();
            for (int row = 0; row < m_vCount; ++row)
            {
                for (int col = 0; col < m_hCount; ++col)
                {
                    Polyline line = m_hexagons[col][row];
                    if (line != null)
                        lst.Add(line);
                }
            }

            return lst;
        }

        public void PointToHex(double px, double py, ref int x, ref int y)
        {
            Matrix m = m_hexagons[0][0].RenderTransform.Value;
            m.Invert();
            Point pt = m.Transform(new Point(px, py));

            // number of half columns
            x = (int)(2 * pt.X / Sqrt2);          // possible half-column
            y = (int)(pt.Y / (1 + InvSqrt2));     // possible row

            // now we will translate (normalize)
            pt.X = pt.X - x * InvSqrt2;
            pt.Y = pt.Y - y * (1 + InvSqrt2);

            if (pt.Y < InvSqrt2)
            {
                // we are not still sure about the row
                if (y % 2 == 0)
                {
                    // begins with left half
                    if ((x % 2 == 0 && InvSqrt2 - pt.X > pt.Y)          // this is left half
                        || (x % 2 == 1 && pt.X > pt.Y))      // this is right haft
                        --y;
                }
                else
                {
                    // begins with right half
                    if ((x % 2 == 0 && pt.X > pt.Y)          // this is right half
                        || (x % 2 == 1 && InvSqrt2 - pt.X > pt.Y))      // this is left haft
                        --y;
                }
            }

            // now we have determined the row
            // make adjustments to the column
            if (y % 2 == 1)
            {
                if (x > 2 * (m_hCount - 1))
                    x = -1;
                else
                    --x;
            }

            if (x >= 0 && x < 2 * m_hCount && y >= 0 && y < m_vCount)
                x /= 2;
            else
                x = y = -1;

/*            // rescale Y
            py /= m_scaleY;

            // number of half columns
            x = (int)(2 * px / m_vertice / Sqrt2);          // possible half-column
            y = (int)(py / m_vertice / (1 + InvSqrt2));     // possible row

            // now we will translate (normalize)
            px = px - x * m_vertice * InvSqrt2;
            py = py - y * m_vertice * (1 + InvSqrt2);

            if (py < m_vertice * InvSqrt2)
            {
                // we are not still sure about the row
                if (y % 2 == 0)
                {
                    // begins with left half
                    if ((x % 2 == 0 && m_vertice * InvSqrt2 - px > py)          // this is left half
                        || (x % 2 == 1 && px > py))      // this is right haft
                        --y;
                }
                else
                {
                    // begins with right half
                    if ((x % 2 == 0 && px > py)          // this is right half
                        || (x % 2 == 1 && m_vertice * InvSqrt2 - px > py))      // this is left haft
                        --y;
                }
            }

            // now we have determined the row
            // make adjustments to the column
            if (y % 2 == 1)
            {
                if (x > 2 * (m_hCount - 1))
                    x = -1;
                else
                    --x;
            }

            if (x >= 0 && x < 2 * m_hCount && y >= 0 && y < m_vCount)
                x /= 2;
            else
                x = y = -1;*/
        }
    }
}
